#include "OS.h"
#include "OSCon.h"
#include "NetFile.h"
#include "pcap.h"

using namespace host;

bool NetFile::Open(const char *name, const char *filter /*= NULL*/)
{
    char errbuf[PCAP_ERRBUF_SIZE];

    /* Open the capture file */
    fp = pcap_open_offline(name, errbuf);
    if (fp == nullptr)
    {
        OSCon::PrintR("Unable to open the file <%s>", name);
        return false;
    }

    return true;
}

bool NetFile::Create(const char *name, const char *filter /*= NULL*/)
{
    return true;
}

bool NetFile::Close()
{
    if(fp)
    {
        pcap_close(fp);
    }

    return true;
}

int NetFile::Next(struct ETHPacket* &packet)
{
    struct pcap_pkthdr *header = nullptr;
    const u_char *data;

    int res = pcap_next_ex(fp, &header, (const u_char**)&data);
    if (res < 0)
    {
        OSCon::PrintR("Error reading the packets: %s", pcap_geterr(fp));
        return res;
    }

    if (header->caplen)
    {
        memcpy(&m_tEthPacket, data, header->caplen);
    }

    packet = &m_tEthPacket;

    return  header->caplen;
}

int NetFile::Next(struct URBPacket* &packet)
{
    struct pcap_pkthdr *header = nullptr;
    const u_char *data;

    int res = pcap_next_ex(fp, &header, (const u_char**)&data);
    if (res < 0)
    {
        OSCon::PrintR("Error reading the packets: %s", pcap_geterr(fp));
        return res;
    }

    if (header->caplen)
    {
        memcpy(&m_tUrbPacket, data, header->caplen);
    }

    packet = &m_tUrbPacket;

    return  header->caplen;
}

int NetIPv4::Next(struct IPv4Packet* &packet)
{
    struct ETHPacket *pEthPkt = nullptr;
    int nPktlen = NetFile::Next(pEthPkt);
    if (nPktlen <= 0)
        return nPktlen;

    packet = &pEthPkt->IPv4Pkt;

    return (nPktlen - ETH_HEAD_SIZE);
}

int NetIPv4::Paser(struct ETHPacket* i_pEthPacket, struct IPv4Packet*& packet)
{
    if (OS::Ntohs(i_pEthPacket->type) != IPV4_TYPE)
        return 0;

    packet = &i_pEthPacket->IPv4Pkt;

    return (OS::Ntohs(packet->length) - (packet->versoin & 0x0F << 2));
}

int NetIPv6::Next(struct IPv6Packet*& packet)
{
    struct ETHPacket* pEthPkt = nullptr;
    int nPktlen = NetFile::Next(pEthPkt);
    if (nPktlen <= 0)
        return nPktlen;

    packet = &pEthPkt->IPv6Pkt;

    return (nPktlen - ETH_HEAD_SIZE);
}

int NetIPv6::Paser(struct ETHPacket* i_pEthPacket, struct IPv6Packet*& packet)
{
    if (OS::Ntohs(i_pEthPacket->type) != IPV6_TYPE)
        return 0;

    packet = &i_pEthPacket->IPv6Pkt;

    return (OS::Ntohs(packet->length));
}

int NetUDP::Next(struct UDPPacket*& packet)
{
    struct ETHPacket* pEthPkt = nullptr;
    struct IPv4Packet* pIPv4Pkt = nullptr;
    struct IPv6Packet* pIPv6Pkt = nullptr;
    int nPktlen = NetFile::Next(pEthPkt);
    if (nPktlen <= 0)
        return nPktlen;

    if (OS::Ntohs(pEthPkt->type) == IPV4_TYPE)
    {
        NetIPv4::Paser(pEthPkt, pIPv4Pkt);
        packet = &pIPv4Pkt->UDPPkt;
        return OS::Ntohs(pIPv4Pkt->length) - ((pIPv4Pkt->versoin & 0x0F) << 2);
    }
    if (OS::Ntohs(pEthPkt->type) == IPV6_TYPE)
    {
        NetIPv6::Paser(pEthPkt, pIPv6Pkt);
        packet = &pIPv6Pkt->UDPPkt;
        return OS::Ntohs(pIPv6Pkt->length);
    }

    return 0;
}

int NetRTP::Next(struct RTPPacket* &packet)
{
    struct UDPPacket *pUdpPkt = nullptr;
    int nPktlen = NetUDP::Next(pUdpPkt);
    if (nPktlen <= 0)
        return nPktlen;

    packet = &pUdpPkt->RTPPkt;
    if ((packet->vpxcc & 0xC0) != 0x80)
        return 0;

    return OS::Ntohs(pUdpPkt->length) - UDP_HEAD_SIZE;
}

host::NetVideo::NetVideo()
{
    m_u32PktNum = 0;
    m_u32FrameFlags = 0;

    m_pVideoBuff = new unsigned char[1024 * 1024]; //1M
    m_u32VideoLen = 0;
}

host::NetVideo::~NetVideo()
{
    delete m_pVideoBuff;
}

bool host::NetVideo::Paser(struct RTPPacket* i_pRtpPkt, int i_nPktLen)
{
    unsigned char *pBuf = (unsigned char*)i_pRtpPkt;

    pBuf += sizeof(unsigned char);
    unsigned char  u8Ptype = *(unsigned char *)pBuf; pBuf += sizeof(unsigned char);
    unsigned short u16Seq  = *(unsigned short*)pBuf; pBuf += sizeof(unsigned short);
    unsigned int   u32Ts   = *(unsigned int  *)pBuf; pBuf += sizeof(unsigned int);
    unsigned int   u32Ssrc = *(unsigned int  *)pBuf; pBuf += sizeof(unsigned int);

    unsigned short extPorf = *(unsigned short*)pBuf; pBuf += sizeof(unsigned short);
    unsigned short extLen  = *(unsigned short*)pBuf; pBuf += sizeof(unsigned short);
    unsigned char  extVer  = *(unsigned char *)pBuf; pBuf += sizeof(unsigned char);
    unsigned char  fmtType = *(unsigned char *)pBuf; pBuf += sizeof(unsigned char);
    unsigned short nResver = *(unsigned short*)pBuf; pBuf += sizeof(unsigned short);

    u16Seq = OS::Ntohs(u16Seq);
    if (!m_u32PktNum)
    {

    }
    else if (u16Seq != (unsigned short)(m_u16LastSeq + 1))
    {
        m_u32FrameFlags = 0;
        OSCon::Print("Packet lost seq:%hu->%hu\n", m_u16LastSeq, u16Seq);
    }
    m_u16LastSeq = u16Seq;

    m_u8FmtType = fmtType;
    m_pRtpPkt = i_pRtpPkt;
    m_u32PktNum++;

    unsigned int nVideoLen = i_nPktLen - (unsigned int)(pBuf - (unsigned char*)i_pRtpPkt);

    switch (fmtType)
    {
        case MEDIA_PK_FULL:
        {
            memcpy(m_pVideoBuff, pBuf, nVideoLen);
            m_u32VideoLen = nVideoLen;
            return true;
        }
        case MEDIA_PK_START:
        {
            m_u32FrameFlags |= MEDIA_PK_START;

            memcpy(m_pVideoBuff, pBuf, nVideoLen);
            m_u32VideoLen = nVideoLen;
            break;
        }
        case MEDIA_PK_MIDDLE:
        {
            if (!(m_u32FrameFlags&MEDIA_PK_START))
                return false;

            memcpy(m_pVideoBuff+ m_u32VideoLen, pBuf, nVideoLen);
            m_u32VideoLen += nVideoLen;
            break;
        }
        case MEDIA_PK_END:
        {
            if (!(m_u32FrameFlags&MEDIA_PK_START))
                return false;

            memcpy(m_pVideoBuff + m_u32VideoLen, pBuf, nVideoLen);
            m_u32VideoLen += nVideoLen;
            return true;
        }
        default:
        {
            OSCon::PrintY("error");
            break;
        }
    }

    return false;
}

int NetUsbAudio::Next(struct URBPacket* &packet)
{
    return NetFile::Next(packet);
}

